﻿using CSharp.Libs.WPF.UserControls.SmarMediaPlayer.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.InteropServices;
using System.Timers;
using System.Windows.Threading;
using System.Windows.Controls.Primitives;
using System.ComponentModel;
using CSharp.Libs.WPF.UserControls.SmartMediaPlayer.Models;



namespace CSharp.Libs.WPF.UserControls.SmartMediaPlayer
{
	public class DoubleClickEventArgs : RoutedEventArgs
	{
		public DoubleClickEventArgs(RoutedEvent routedEvent, object source)
			: base(routedEvent, source)
		{ }
	}

    #region event handlers
	public delegate void CurrentMediaChangedEventDelegate(object sender, CurrentMediaPositionEventArgs ea);
	public class CurrentMediaPositionEventArgs : CurrentMediaEventArgs
	{
		public TimeSpan CurrentPosition { get; set; }
	}

	public delegate void CurrentMediaEndedEventDelegate(object sender, CurrentMediaEventArgs ea);
	public class CurrentMediaEventArgs : EventArgs
	{
		public PlaylistItem CurrentItem { get; set; }
	}
	#endregion


	/// <summary>
	/// Interaktionslogik für Player.xaml
	/// </summary>
	public partial class Player : UserControl
	{
		#region declarations
		private PlayerViewModel _vm;
        private DispatcherTimer _timerVideoTime;

		private CurrentMediaPositionEventArgs eaCurrentMediaPosition;

        private const string ICON_PLAY = "icoPlay";
        private const string ICON_PAUSE = "icoPause";
        private const double ICON_SIZE = 32;

		#region events
		public event CurrentMediaChangedEventDelegate CurrentMediaChanged;
		protected void OnCurrentMediaChanged(
			CurrentMediaPositionEventArgs ea)
		{
			if (CurrentMediaChanged != null)
			{
				CurrentMediaChanged(this, ea);
			}
		}

		public event CurrentMediaEndedEventDelegate CurrentMediaEnded;
		protected void OnCurrentMediaEnded(
			CurrentMediaEventArgs ea)
		{
			if (CurrentMediaEnded != null)
			{
				CurrentMediaEnded(this, ea);
			}
		}
		#endregion
		
		#region fullscreen support
		[DllImport("user32.dll")]
		static extern uint GetDoubleClickTime();

		public static readonly RoutedEvent DoubleClickEvent =
		EventManager.RegisterRoutedEvent(
			"DoubleClick",
			RoutingStrategy.Bubble,
			typeof(RoutedEventHandler),
			typeof(Player));

		public event RoutedEventHandler DoubleClick
		{
			add { AddHandler(DoubleClickEvent, value); }
			remove { RemoveHandler(DoubleClickEvent, value); }
		}

		Timer timeClick = new Timer((int)GetDoubleClickTime())
		{
			AutoReset = false,
		};

		bool _fullScreen = false;
		#endregion

		#endregion



		#region constructor
		public Player()
		{
			InitializeComponent();

			Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted;

			_vm = new PlayerViewModel();
			DataContext = _vm;

			VM.PropertyChanged += VM_PropertyChanged;

            // Create a timer that will update the counters and the time slider
            _timerVideoTime = new DispatcherTimer();
            _timerVideoTime.Interval = TimeSpan.FromSeconds(1);
            _timerVideoTime.Tick += new EventHandler(timer_Tick);
        }

		void Dispatcher_ShutdownStarted(object sender, EventArgs e)
		{
            _timerVideoTime.Tick -= timer_Tick;
            _timerVideoTime = null;

            VM.PropertyChanged -= VM_PropertyChanged;

			Dispatcher.ShutdownStarted -= Dispatcher_ShutdownStarted;
			DataContext = null;
			_vm.Shutdown();
			_vm = null;
		}
		#endregion



		#region eventhandling
		#region fullscreen support
		private void mePlayer_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
		{
			if (!timeClick.Enabled)
			{
				timeClick.Enabled = true;
				return;
			}

			if (timeClick.Enabled)
			{
				_fullScreen = !_fullScreen;

				if (_fullScreen)
				{
					this.Background = new SolidColorBrush(Colors.Black);
				}
				else
				{
					this.Background = new SolidColorBrush(Colors.White);
				}

				RaiseEvent(new DoubleClickEventArgs(Player.DoubleClickEvent, this));
			}
		}
		#endregion

		#region slider support
		private TimeSpan TotalTime;
		private bool _isThumbDragging = false;

		void timer_Tick(object sender, EventArgs e)
		{
			// Check if the movie finished calculate it's total time
			if (mePlayer.NaturalDuration.HasTimeSpan &&
                mePlayer.NaturalDuration.TimeSpan.TotalSeconds > 0)
			{
				if (TotalTime.TotalSeconds > 0)
				{
					if (!_isThumbDragging)
					{
						// Updating time slider
						timeSlider.Value = mePlayer.Position.TotalSeconds;
						lblCurrentTime.Content = mePlayer.Position.ToString(@"hh\:mm\:ss");
					}
					else
					{
						lblCurrentTime.Content = TimeSpan.FromSeconds(timeSlider.Value).ToString(@"hh\:mm\:ss");
						mePlayer.Position = TimeSpan.FromSeconds((int)timeSlider.Value);
					}
					
					//Update event args current position
					eaCurrentMediaPosition.CurrentPosition = mePlayer.Position;
					//throw event
					OnCurrentMediaChanged(eaCurrentMediaPosition);
				}
			}
		}

		private void timeSlider_DragStarted(object sender, DragStartedEventArgs e)
		{
			//set dragging switch
			_isThumbDragging = true;
			
			//if player was playing, pause it
			if (_timerVideoTime.IsEnabled)
			{
				mePlayer.Pause();
			}
		}

		private void timeSlider_DragCompleted(object sender, DragCompletedEventArgs e)
		{
			//set dragging switch
			_isThumbDragging = false;

			//update player position 
			mePlayer.Position = TimeSpan.FromSeconds((int)timeSlider.Value);
	
			//if player was playing, continue playing
			if (_timerVideoTime.IsEnabled)
			{
				mePlayer.Play();
			}
		}

		private void timeSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
		{
			//if dragging, update current time position label
			if (_isThumbDragging)
			{
				lblCurrentTime.Content = TimeSpan.FromSeconds(timeSlider.Value).ToString(@"hh\:mm\:ss");
			}
		}
		#endregion

		private void mePlayer_MediaOpened(object sender, RoutedEventArgs e)
		{
			TotalTime = mePlayer.NaturalDuration.TimeSpan;
			timeSlider.Maximum = TotalTime.TotalSeconds;
			timeSlider.SmallChange = 1;
			timeSlider.LargeChange = Math.Min(10, TotalTime.Seconds / 10);
			lblTotalTime.Content = TotalTime.ToString(@"hh\:mm\:ss");
		}

		private void mePlayer_MediaEnded(object sender, RoutedEventArgs e)
		{
			//MessageBox.Show("MediaEnded event fired");
			//Fire event and get next Item to play
			OnCurrentMediaEnded(new CurrentMediaEventArgs() { CurrentItem = VM.CurrentItem });
		}

		void VM_PropertyChanged(object sender, PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "MediaSource")
			{
				//init stuff when media source of player is updated
				_initCurrentMediaEventArgs();

				//set player to position if given
				if (VM.CurrentItem.LastPosition > 0)
				{
					mePlayer.Position = TimeSpan.FromSeconds(VM.CurrentItem.LastPosition);
				}
				
				//if video is still playing, stop it
				if (_timerVideoTime.IsEnabled)
				{
					_stopMedia();
				}

				//[Option]Autoplay
				_playPauseMedia();
			}
		}

        private void btnPlayPause_Click(object sender, RoutedEventArgs e)
        {
            _playPauseMedia();
        }

        private void btnStop_Click(object sender, RoutedEventArgs e)
        {
            _stopMedia();
        }
        #endregion



		#region private functions
		private void _playPauseMedia()
		{
            if (_timerVideoTime.IsEnabled)
            {
                mePlayer.Pause();
                btnPlayPause.Content = new Image { Source = (ImageSource)FindResource(ICON_PLAY), Width = ICON_SIZE, Height = ICON_SIZE };
                _timerVideoTime.Stop();
            }
            else
            {
                mePlayer.Play();
                btnPlayPause.Content = new Image { Source = (ImageSource)FindResource(ICON_PAUSE), Width = ICON_SIZE, Height = ICON_SIZE };
                _timerVideoTime.Start();
            }
        }

		private void _stopMedia()
		{
			mePlayer.Position = TimeSpan.FromSeconds(0);
			mePlayer.Stop();
            timeSlider.Value = 0;
            lblCurrentTime.Content = TimeSpan.FromSeconds(0).ToString(@"hh\:mm\:ss");
            btnPlayPause.Content = new Image { Source = (ImageSource)FindResource(ICON_PLAY), Width = ICON_SIZE, Height = ICON_SIZE };
            _timerVideoTime.Stop();
		}

		private void _initCurrentMediaEventArgs()
		{
			if (eaCurrentMediaPosition == null)
			{
				eaCurrentMediaPosition = new CurrentMediaPositionEventArgs();
			}

			if (eaCurrentMediaPosition.CurrentItem != VM.CurrentItem)
			{
				eaCurrentMediaPosition.CurrentItem = VM.CurrentItem;
			}

			eaCurrentMediaPosition.CurrentPosition = new TimeSpan(0);

            //throw event
            OnCurrentMediaChanged(eaCurrentMediaPosition);
        }
		#endregion



		#region properties
		public PlayerViewModel VM { get { return _vm; } }

		public bool FullScreen { get { return _fullScreen; } }
		#endregion



		#region tests
		private void Canvas_MouseEnter(object sender, MouseEventArgs e)
		{

		}

		private void Canvas_MouseLeave(object sender, MouseEventArgs e)
		{

		}






		#endregion
	}
}



/* alternativer Versuch ohne Timer
bool _fSecondClick = false;
DateTime _dateLastClick = DateTime.MinValue;
private void MediaElement_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    if (!_fSecondClick)
    {
        _fSecondClick = true;
        _dateLastClick = DateTime.Now;
    }
    else
    {
        if ((DateTime.Now - _dateLastClick).Milliseconds <= GetDoubleClickTime())
        {
            fullScreen = !fullScreen;
            RaiseEvent(new DoubleClickEventArgs(Player.DoubleClickEvent, this));
        }
        _fSecondClick = false;
    }

    if (!fullScreen)
    {
        this.Background = new SolidColorBrush(Colors.Black);
    }
    else
    {
        this.Background = new SolidColorBrush(Colors.White);
    }
}*/

